package cool.tianyou.blue.bird.module.synchronize.service;

import cn.hutool.extra.spring.SpringUtil;
import cool.tianyou.blue.bird.common.exception.DeviceNotFoundException;
import cool.tianyou.blue.bird.common.mapper.DeviceMapper;
import cool.tianyou.blue.bird.common.model.po.Device;
import cool.tianyou.blue.bird.common.tool.LocalCache;
import cool.tianyou.blue.bird.common.util.Assert;
import cool.tianyou.blue.bird.config.PrometheusCustomMonitor;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.util.Sqls;

/**
 * @author Liutianyou
 * @date 2021/7/18 6:34 下午
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class DeviceService {

  final DeviceMapper deviceMapper;
  final JmsService jmsService;
  final WebSocketService webSocketService;
  final LocalCache localCache;
  final PrometheusCustomMonitor monitor;

  @CacheEvict(cacheNames = "device", key = "'BB:DEVICE'+#userId")
  public Boolean updatePublicKey(String deviceName, String publicKey, Integer userId) {
    int result = 0;
    Example example = new Example(Device.class);
    example.createCriteria()
        .andEqualTo("deviceName", deviceName)
        .andEqualTo("userId", userId);
    List<Device> devices = deviceMapper.selectByExample(example);
    if (!devices.isEmpty()) {
      devices.get(0).setPublicKey(publicKey);
      result = deviceMapper.updateByPrimaryKeySelective(devices.get(0));
    }
    return result > 0;
  }

  @PostConstruct
  public void setGauge() {
    monitor.clientCount(this.deviceMapper.count());
  }

  public Boolean updatePublicKey(Integer deviceId, String publicKey) {
    int result = 0;
    Device device = deviceMapper.selectByPrimaryKey(deviceId);
    if (device != null) {
      device.setPublicKey(publicKey);
      result = deviceMapper.updateByPrimaryKey(device);
      jmsService.sendUpdatePublicKeyMessage(device);
      SpringUtil.getBean(DeviceService.class).clearCache(device.getUserId());
    }
    return result > 0;
  }

  public void requestUnlock(Integer deviceId) {
    jmsService.sendRequestUnlockMessage(deviceMapper.selectByPrimaryKey(deviceId));
  }

  /**
   * 获取所有的上线的设备
   *
   * @param userId 用户id
   * @return 用户上线的所有设备
   */
  public List<Device> findByUserId(Integer userId) {
    DeviceService service = SpringUtil.getBean(DeviceService.class);
    List<Device> devices = service.getDeviceByUserId(userId);
    return devices.stream().filter(device ->
        Objects.equals(device.getDisabled(), false)
            && Objects.equals(device.getOnline(), true)
            && device.getPublicKey() != null)
        .collect(Collectors.toList());

  }

  /**
   * 根据ID获取设备
   *
   * @param userId 用户id
   * @return 用户上线的所有设备
   */
  public Optional<Device> findByUserIdAndId(Integer userId, Integer deviceId) {
    DeviceService service = SpringUtil.getBean(DeviceService.class);
    List<Device> devices = service.getDeviceByUserId(userId);
    return devices.stream()
        .filter(device -> Objects.equals(deviceId, device.getId()))
        .collect(Collectors.toList()).stream().findAny();

  }

  public List<Device> findAllByUserId(Integer userId) {
    DeviceService service = SpringUtil.getBean(DeviceService.class);
    return service.getDeviceByUserId(userId);
  }

  @CacheEvict(cacheNames = "device", key = "'BB:DEVICE'+#userId")
  public void toggleStatus(Integer deviceId, Integer userId, Boolean lock) {
    List<Device> devices = deviceMapper.selectByExample(Example.builder(Device.class)
        .where(Sqls.custom()
            .andEqualTo("userId", userId)
            .andEqualTo("id", deviceId)).build());
    Assert.notEmpty(devices, new DeviceNotFoundException());
    Device device = devices.get(0);
    device.setDisabled(lock);
    deviceMapper.updateByPrimaryKeySelective(device);
    //发送消息 通知客户端回显禁用状态
    webSocketService.notifyLockStatus(userId, deviceId, lock);

  }

  @CacheEvict(cacheNames = "device", key = "'BB:DEVICE'+#userId")
  public void changeAlias(Integer deviceId, String newName, Integer userId) {

    Device device = deviceMapper.selectByPrimaryKey(deviceId);
    Assert.notNull(device, new DeviceNotFoundException());
    Assert.isTrue(device.getUserId().equals(userId), new DeviceNotFoundException());
    device.setAlias(newName);
    deviceMapper.updateByPrimaryKeySelective(device);

    localCache.updateDeviceAlias(deviceId, newName);
  }

  @CacheEvict(cacheNames = "device", key = "'BB:DEVICE'+#userId")
  public void offLineDevice(Integer deviceId, Integer userId) {
    Device device = deviceMapper.selectByPrimaryKey(deviceId);
    Assert.notNull(device, new DeviceNotFoundException());
    Assert.isTrue(device.getUserId().equals(userId), new DeviceNotFoundException());
    device.setOnline(false);

    //移除登录状态
    localCache.removeByDeviceId(userId, deviceId);
    //发送消息让客户端下线
    webSocketService.notifyOffline(userId, deviceId);
//    webSocketService.removeSession(userId, deviceId);
  }

  @CacheEvict(cacheNames = "device", key = "'BB:DEVICE'+#userId")
  public void delete(Integer deviceId, Integer userId) {
    offLineDevice(deviceId, userId);
    List<Device> devices = deviceMapper.selectByExample(
        Example.builder(Device.class)
            .where(Sqls.custom()
                .andEqualTo("userId", userId).andEqualTo("id", deviceId)).build());
    Assert.notEmpty(devices, new DeviceNotFoundException());
    deviceMapper.deleteByPrimaryKey(deviceId);
  }

  @CacheEvict(cacheNames = "device", key = "'BB:DEVICE'+#userId")
  public void releaseCache(Integer userId) {
  }

  @Cacheable(cacheNames = "device", key = "'BB:DEVICE'+#userId")
  public List<Device> getDeviceByUserId(Integer userId) {
    log.info("从数据库查询设备信息：{}", userId);
    return deviceMapper.selectByExample(
        Example.builder(Device.class)
            .where(Sqls.custom()
                .andEqualTo("userId", userId)).build());
  }


  /**
   * 同步设备的 消息推送开关状态
   *
   * @param deviceId  设备id
   * @param pushState 推送状态
   */
  public void changeDevicePushState(Integer deviceId, Boolean pushState) {
    Device device = deviceMapper.selectByPrimaryKey(deviceId);
    if (device != null) {
      device.setPushState(pushState);
      deviceMapper.updateByPrimaryKey(device);
      webSocketService.notifyPushState(device.getUserId(), deviceId, pushState);
    }
  }

  @CacheEvict(cacheNames = "device", key = "'BB:DEVICE'+#userId")
  public void clearCache(Integer userId) {

  }


}
